package com.huoxingy.print.domain;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.List;

/**
 * Created by hanxi on 2017/12/25.·
 */
@Slf4j
public class NetPrinter {
    private String ip;
    private short port;

    public NetPrinter(String ip, short port) {
        this.ip = ip;
        this.port = port;
    }

    public boolean print(List<OrderPrintTask> tasks) {
        Socket socket = null;
        try {
            socket = new Socket();

            for (int i = 0; i < 5; i++) {
                try {
                    log.info("Try to connect printer {}:{} at {} time...", this.ip, this.port, i + 1);
                    socket.connect(new InetSocketAddress(this.ip, this.port), 5000);
                    break;
                } catch (Exception e) {
                    log.warn("Fail to connect to printer {}:{} failed, the cause is:{}, retry...", this.ip, this.port, e.getMessage());
                }
            }
            if (socket.isConnected()) {
                log.info("Printer {}:{} connected", this.ip, this.port);

                try {
                    process(socket, tasks);
                    return true;
                } catch (IOException e) {
                    log.error("Fail to send data to printer {}:{}, the error message is:{}", this.ip, this.port, e.getMessage());
                    return false;
                }

            } else {
                log.warn("Fail to connect to printer {}:{}, quit the print task, retry later", this.ip, this.port);
                return false;
            }

        } catch (Exception e) {
            log.error("Fail to print task!", e);

        } finally {
            if (null != socket) {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.error("Failt to close socket!");
                }
            }
        }
        return false;
    }

    private void process(Socket socket, List<OrderPrintTask> tasks) throws IOException {
        OutputStream output = null;
        try {
            output = socket.getOutputStream();

            ByteBuffer bb = ByteBuffer.allocate(1024);
            // 设置汉字打印
            bb.put(new byte[]{0x1c, 0x26});
            // 加粗
            bb.put(new byte[]{0x1b, 0x21, 0x08});

            for (OrderPrintTask task : tasks) {
                // 倍宽和倍高
                bb.put(new byte[]{0x1d, 0x21, 0x22});
                String tableNo = task.getTableNo();
                if (StringUtils.isEmpty(tableNo)) {
                    tableNo = "未知";
                }
                bb.put(String.format("桌号：%1$s", tableNo).getBytes("GBK"));

                // 打印并走纸
                bb.put(new byte[]{0x1b, 0x64, 0x02});

                // 取消倍宽和倍高
                bb.put(new byte[]{0x1d, 0x21, 0x00});
                bb.put((byte) 0x0a);
                bb.put(String.format("订单号：%1$s", task.getOrderCode()).getBytes("GBK"));
                bb.put((byte) 0x0a);
                bb.put(String.format("下单人：%1$s", task.getCreatorName()).getBytes("GBK"));
                bb.put((byte) 0x0a);
                bb.put(String.format("下单时间：%1$s", task.getCreateTime()).getBytes("GBK"));
                bb.put((byte) 0x0a);
                bb.put(String.format("打印时间：%1$s", task.getPrintTime()).getBytes("GBK"));
                // 打印并走纸
                bb.put(new byte[]{0x1b, 0x64, 0x02});

                // 倍宽和倍高
                bb.put(new byte[]{0x1d, 0x21, 0x22});
                bb.put(String.format("%1$s（%2$s份），共%3$s元", task.getProductName(), task.getQuantity(), task.getPrice()).getBytes("GBK"));
                // 打印并走纸
                bb.put(new byte[]{0x1b, 0x64, 0x02});

                // 倍宽和倍高
                if (!StringUtils.isEmpty(task.getNotes())) {
                    bb.put(new byte[]{0x1d, 0x21, 0x11});
                    bb.put(String.format("备注：%1$s", task.getNotes()).getBytes("GBK"));
                }
                // 打印并走纸
                bb.put(new byte[]{0x1b, 0x64, 0x07});

                // 切纸
                bb.put(new byte[]{0x1d, 0x56, 0x00});
            }

            bb.flip();

            byte[] dst = new byte[bb.limit()];
            bb.get(dst);

            output.write(dst);
            output.write(dst);

            output.flush();
        } finally {
            if (null != output) {
                output.close();
            }
        }
    }
}
